import os
import pickle
import time

import numpy as np
import tensorflow as tf
from tensorflow import keras

from src.mobile.model import mobile_model_config
from src.mobile.predict.mobile_price_config import MODEL_DIR, MAX_EVN_PRICE, \
    HISTORY_AVG_PRICE_WEIGHT, MODEL_PRICE_WEIGHT
from src.utils.config import logger
from src.utils.model_utils import load_history_avg_price
from src.utils.model_utils import getMape,custom_mean_absolute_percentage

from tensorflow.python.keras.backend import set_session
session_config = tf.ConfigProto(allow_soft_placement=True)
sess = tf.Session(config=session_config)
global graph
graph = tf.get_default_graph()


class MobilePredictor:
    def __init__(self):
        # 模型
        self.model = None
        # 特征变量One-Hot编码处理器
        self.ohe = None
        self.product_ohe = None
        # 价格标准化
        self.scaler = None

        self.load_models()

    def load_models(self):
        """
        读取模型和预处理器
        :return:
        """
        logger.info('loading models...')

        model_file = os.path.join(MODEL_DIR, mobile_model_config.MODEL_FILE_NAME)
        with graph.as_default():
            set_session(sess)
            # self.model = keras.models.load_model(model_file)
            self.model = keras.models.load_model(model_file, custom_objects={
                'custom_mean_absolute_percentage': custom_mean_absolute_percentage,
                'leaky_relu': tf.nn.leaky_relu})

        ohe_file = os.path.join(MODEL_DIR, mobile_model_config.MOBILE_OHE_NAME)
        with open(ohe_file, 'rb') as f:
            self.ohe = pickle.load(f)

        scaler_file = os.path.join(MODEL_DIR, mobile_model_config.MOBILE_SCALER_NAME)
        with open(scaler_file, 'rb') as f:
            self.scaler = pickle.load(f)

        product_ohe_file = os.path.join(MODEL_DIR, mobile_model_config.MOBILE_PRODUCT_OHE_NAME)
        with open(product_ohe_file, 'rb') as f:
            self.product_ohe = pickle.load(f)

        logger.info('loading models done')

    def predict_price(self, predict_data):
        """
        预测价格
        :param predict_data: 数据，经过model_data预处理格式
        :return:
        """
        predict_data['period'] = '0'

        predict_x_inputs = self.ohe.transform(predict_data[mobile_model_config.MOBILE_FEATURES])

        logger.info('predict price')
        t1 = time.time()
        with graph.as_default():
            set_session(sess)
            predict_price = self.model.predict(predict_x_inputs)
        t2 = time.time()
        logger.info('predict price use time @{}'.format(t2-t1))
        # predict_data['price'] = np.round(
        #     self.scaler.inverse_transform(predict_price.reshape((-1, 1))).flatten()).astype(int)

        predict_data['price'] = np.round(
            predict_price.flatten(-1)).astype(int)

        # 处理和均价的加权
        predict_data['key'] = mobile_model_config.MOBILE_HISTORY_AVG_PRICE_PREFIX + \
            predict_data['sku_id'].astype(str) + '_' + predict_data['level_id'].astype(str)
        predict_data['history_avg_price'] = [load_history_avg_price(k) for k in predict_data['key']]
        predict_data['history_avg_price'] = predict_data['history_avg_price'].where(
            predict_data['history_avg_price'].notnull(), predict_data['price'])
        predict_data['price'] = predict_data['price'] * MODEL_PRICE_WEIGHT + \
            predict_data['history_avg_price'] * HISTORY_AVG_PRICE_WEIGHT

        predict_data['is_new_product'] = self.product_ohe.transform(
            predict_data[['product_name']]).sum(axis=1).astype(int)
        predict_data['is_new_product'] = predict_data['is_new_product'].replace({0: 1, 1: 0})

        # 处理环保机报价
        # env_protect = (predict_data['product_level_template_id'] == mobile_model_config.EVN_TEMPLATE_ID) \
        #               & (predict_data['is_new_product'] == 1)
        env_protect = predict_data['product_level_template_id'] == mobile_model_config.EVN_TEMPLATE_ID
        predict_data.loc[env_protect, 'price'] = predict_data.loc[
            env_protect, 'price'].where(predict_data.loc[env_protect, 'price'] <= MAX_EVN_PRICE, MAX_EVN_PRICE)
        # 处理最小值
        predict_data['price'] = predict_data['price'].where(predict_data['price'] >= 5, 5)

        predict_data['price'] = predict_data['price'].astype(np.int)
        predict_data['category'] = 1
        return predict_data[['category', 'product_id', 'sku_id', 'price', 'level_id', 'brand_id',
                             'is_new_product']].astype('object').to_dict('records')
